#include "I2C_SOFT_GPIO.h"
#include "My_Own_SOFT_I2C_FOR_OLED.h"
#include <string.h>
/**
@param command_control_type 从机 I2C 传输命令时的控制类型
@param data_control_type从机 I2C 传输数据时的控制类型
*/
const static uint8_t slave_address = 0x3c;
const uint8_t command_control_type=0x00;
const uint8_t data_control_type=0x40;


void write_data(const uint8_t * data,const uint8_t data_count){
    
    uint8_t total_data_count = data_count+1;
    
    uint8_t data_with_command[total_data_count];
    
    data_with_command[0] = data_control_type;
    
    for(uint8_t i=1;i<total_data_count;i++){
        data_with_command[i] = data[i-1];
    }
    
    write(slave_address,data_with_command,total_data_count);

}



void write_command(uint8_t command){
    
    
    write(slave_address,(uint8_t[]){command_control_type,command},2);
  

}
void write_command_n_byte(uint8_t * command,uint8_t command_count){

    uint8_t total_command_count = command_count+1;
    
    uint8_t command_with_command[total_command_count];
    
    command_with_command[0] = command_control_type;
    
    for(uint8_t i=1;i<total_command_count;i++){
        command_with_command[i] = command[i-1];
    }
    
	write(slave_address,command_with_command,total_command_count);

}
void clear_screen(void){

// 水平扫描模式
	write_command_n_byte((uint8_t[]){0x20,0x00},2);
   
	
	/* 设置行的范围 设定为从第一行到第64行
	
	*/
	write_command_n_byte((uint8_t[]){0x22,0,7},3);
	
	/* 设置列的范围 设定为从第一列到第128列
		
	*/
	write_command_n_byte((uint8_t[]){0x21,0,127},3);
    
    // 因为在 while 中单次发送16字节的数据，所以这里要除以16
    uint16_t count = 128*8/16; 
    
    uint8_t blank_byte[] = {
        
        0,0,0,0,
        0,0,0,0,
        0,0,0,0,
        0,0,0,0,
    };
    
    while(count>0){
    
        write_data(blank_byte,16);
        count--;
    }
	
}



void init_oled(void){

	
	write_command(0xAE);	//关闭显示
	
	write_command(0xD5);	//设置显示时钟分频比/振荡器频率
	write_command(0x80);
	
	write_command(0xA8);	//设置多路复用率
	write_command(0x3F);
	
	write_command(0xD3);	//设置显示偏移
	write_command(0x00);
	
	write_command(0x40);	//设置显示开始行
	
	write_command(0xA1);	//设置左右方向，0xA1正常 0xA0左右反置
	
	write_command(0xC8);	//设置上下方向，0xC8正常 0xC0上下反置

	write_command(0xDA);	//设置COM引脚硬件配置
	write_command(0x12);
	
	write_command(0x81);	//设置对比度控制
	write_command(0xCF);

	write_command(0xD9);	//设置预充电周期
	write_command(0xF1);

	write_command(0xDB);	//设置VCOMH取消选择级别
	write_command(0x30);

	write_command(0xA4);	//设置整个显示打开/关闭

	write_command(0xA6);	//设置正常/倒转显示

	write_command(0x8D);	//设置充电泵
	write_command(0x14);
	
	
	/***************/

    clear_screen();
	/****************/
	write_command(0xAF);	//开启显示

}


void show_fixed_length_string(const uint8_t row,const uint8_t column,const uint8_t * str,const uint8_t fixed_string_length){


	// 水平扫描模式
	write_command_n_byte((uint8_t[]){0x20,0x00},2);

	/* 每一个字的高度为16个像素，宽度为8个像素
		oled 高 64 个像素，宽 128个像素
	因为 高度只能设置为 0-7 ，
	64/8=8 每传送一个字节的数据刚好 能填充一列的8个像素
	传送8个字节刚好能填充屏幕的一整列
	
	
	*/
	
	/* 设置行的范围 高16个像素，也就是每传完2个字节就要把指针重定向到第一行
	
	*/
	write_command_n_byte((uint8_t[]){0x22,row*2,row*2+2},3);
	
	/* 设置列的范围 宽8个像素
		
	*/
	write_command_n_byte((uint8_t[]){0x21,column*8,column*8+8*fixed_string_length},3);
	

	const uint8_t * temp = str;
    

    
	for(uint8_t i=0;i<fixed_string_length;i++){
	
		// asc2 表中 前32个都是控制字符
		// 字体库是从 第33个字符开始的
		const uint8_t * f = OLED_F8x16[*temp - 32];
		
		// 因为是水平扫描模式，且一个字符占两行
		// 所以打印字符串的时候，要先把第一行（字符的上半部分）先打印
		// 然后再把指针跳转到第二行，第二行显示字符的下半部分
		// 前8个字符为上半部分
        
		write_data(f,8);
		temp++;
	}
	
	temp = str;
	

	for(uint8_t i=0;i<fixed_string_length;i++){
	
		// asc2 表中 前32个都是控制字符
		// 字体库是从 第33个字符开始的
		const uint8_t * f = OLED_F8x16[*temp - 32];
		
		// 显示后8个字符为 字符的下半部分
        
     
        
		write_data(f+8,8);
		temp++;
	}

}

void show_string(const uint8_t row,const uint8_t column,const uint8_t * str){
	
	const uint8_t * ch = str;
	
	uint8_t length=0;
	while(*ch != 0 ){
		length++;
		ch++;
	}
	
    show_fixed_length_string(row,column,str,length);    
}	


void show_decimal(const uint8_t row,const uint8_t column, int16_t dec_num){

   
    
    uint8_t str[7]={0,0,0,0,0,0,0};
    
    // 如果为1，代表已经找到第一个有效数字
    uint8_t found_first_valid_number=0;
    
    // 判断输入的数是否为负数
    uint8_t is_negative = dec_num<0;
    
    if(is_negative){
        // 对负数进行操作前，先取绝对值
        dec_num=-dec_num;
    }
    
    uint8_t first_valid_number_location=0;
    
    for(uint16_t i=10000,bit=1;i>0;i/=10,bit++){
    
        uint8_t n = dec_num / i;
        
        if(found_first_valid_number==1||n>0){
            
            str[bit] = n+48;
            
            if(first_valid_number_location==0){
                
                first_valid_number_location = bit;
            }
            
            found_first_valid_number=1;
        }
        
        dec_num%=i;
    }
    if(is_negative){
        // 是负数，在负数有效数字之前添加 负号
        str[first_valid_number_location-1] = '-';
    }
    
    str[6]=0; // 字符串的最后一位是 0
    
    uint8_t * num_str = str;

    while(*num_str==0){
        
        num_str++;
    }
    
    show_fixed_length_string(row,column,str,6);
}
